import traceback

import time
from kubernetes import client
from kubernetes.client import CoreV1Api, V1Scale
from ygframe.logger import logger

from model.mongo_model.resource_info import ResourceInfo, Status
from util.kube_util.kube_builder import RcBuilder, TemplateBuilder, ContainerBuilder, ImagePullPolicy

__author__ = 'jing'


def get_rc(resource_info: ResourceInfo):
    rid = resource_info.resource_id
    uid = resource_info.user_id
    rtype = resource_info.resource_type
    image = resource_info.image
    cport = resource_info.container_port
    hport = resource_info.host_port
    env = resource_info.env
    cmd = resource_info.cmd
    args = resource_info.args
    limits = resource_info.limits
    requests = resource_info.requests

    c = ContainerBuilder()
    c.name(rid).image(image).image_pull_policy(
        ImagePullPolicy.IF_NOT_PRESENT
    ).privileged().port(
        container_port=cport, host_port=hport
    )
    if env:
        c.env(env)
    if cmd:
        c.cmd(cmd)
    if args:
        c.args(args)
    if limits:
        c.limits(limits)
    if requests:
        c.requests(requests)

    rc = RcBuilder()
    rc.name(rid).label(
        uid=uid,
        resourceId=rid,
        resourceType=rtype
    ).replicas(1).selector(resourceId=rid).template(
        TemplateBuilder().label(
            uid=uid,
            resourceId=rid,
            resourceType=rtype
        ).container(c.get()).get()
    )
    return rc.get()


def ensure_namespace(api: CoreV1Api, ns):
    if ns not in [x.metadata.name for x in api.list_namespace().items]:
        api.create_namespace(dict(
            apiVersion='v1',
            kind='Namespace',
            metadata=dict(name=ns)
        ))


def get_ip(api: CoreV1Api, resource_info: ResourceInfo):
    # todo this is a temporary solution
    for pod in api.list_namespaced_pod(resource_info.user_id).items:
        if pod.metadata.name.startswith(resource_info.resource_id):
            i = 0
            while not pod.status.host_ip and i < 20:
                time.sleep(1)
                i += 1
            return pod.status.host_ip


def create_rc(resource_info: ResourceInfo):
    logger.info('creating rc:{}'.format(resource_info.resource_id))
    logger.debug(get_rc(resource_info))
    api = client.CoreV1Api()
    ensure_namespace(api, resource_info.user_id)
    api.create_namespaced_replication_controller(
        resource_info.user_id,
        get_rc(resource_info)
    )


def release_rc(resource_info: ResourceInfo):
    logger.info('releasing rc:{}'.format(resource_info.resource_id))
    api = client.CoreV1Api()
    rid = resource_info.resource_id
    uid = resource_info.user_id
    try:  # todo exception check per call
        ensure_namespace(api, uid)
        api.read_namespaced_replication_controller(rid, uid)
        sc = api.read_namespaced_replication_controller_scale(rid, uid)  # type:V1Scale
        sc.spec.replicas = 0
        api.replace_namespaced_replication_controller_scale(rid, uid, sc)
        api.delete_namespaced_replication_controller(rid, uid, {})
        ResourceInfo.query().filter(
            ResourceInfo.resource_id == rid
        ).first().update(
            ResourceInfo.create_update_builder().set(
                status=Status.RELEASED
            ).get()
        )
        logger.info('deleted rc:{}'.format(resource_info.resource_id))
    except:
        logger.debug(traceback.format_exc())
        pass
